#ifndef __LOGGER_H__
#define __LOGGER_H__

#include "framework_config.h"
#include "loggerdef.h"
#include "messagebuilder.h"
#include "os/mutex.h"
#include "os/thread.h"
#include "os/msgqueue.h"
#include "lib/cqueue.h"
#include "soc/interface/if_soc_uart.h"

//定义Logger
//arg ... 支持一个参数 tag 
#if LOGGER_CONFIG_SHOW_SRC_INFO_EN > 0
#define LogOut(logger, level, ...)  logger.OutputArg(level, __FILE__, __LINE__, __func__, ## __VA_ARGS__)
#else 
#define LogOut(logger, level, ...)  logger.OutputArg(level, ## __VA_ARGS__)
#endif 

//空输出
#define OUT_EMPTY()     MessageBuilder(nullptr)

//定义默认Logger
#if LOGGER_CONFIG_LEVEL >= LOGGER_LEVEL_DEBUG
#define LogDebug(...)        LogOut(Logger::Instance(), LoggerLevel::Debug, ## __VA_ARGS__)
#define LogDebugIf(cond, ...)   if(cond) LogOut(Logger::Instance(), LoggerLevel::Debug, ## __VA_ARGS__)
#else 
#define LogDebug(...)   OUT_EMPTY()
#define LogDebugIf(cond, ...)   OUT_EMPTY()
#endif

#if LOGGER_CONFIG_LEVEL >= LOGGER_LEVEL_INFO
#define LogInfo(...)         LogOut(Logger::instance(), LoggerLevel::Info, ## __VA_ARGS__)
#define LogInfoIf(cond, ...)       if(cond) LogOut(Logger::instance(), LoggerLevel::Info, ## __VA_ARGS__)
#else 
#define LogInfo(...)    OUT_EMPTY()
#define LogInfoIf(...)  OUT_EMPTY() 
#endif

#if LOGGER_CONFIG_LEVEL >= LOGGER_LEVEL_WARN
#define LogWarn(...)         LogOut(Logger::Instance(), LoggerLevel::Warn, ## __VA_ARGS__)
#define LogWarnIf(cond, ...)         if(cond)LogOut(Logger::Instance(), LoggerLevel::Warn, ## __VA_ARGS__)
#else 
#define LogWarn(...)    OUT_EMPTY()
#define LogWarnIf(cond, ...)    OUT_EMPTY()
#endif

#if LOGGER_CONFIG_LEVEL >= LOGGER_LEVEL_ERROR
#define LogError(...)        LogOut(Logger::Instance(), LoggerLevel::Error, ## __VA_ARGS__)
#define LogErrorIf(cond, ...)        if(cond)LogOut(Logger::Instance(), LoggerLevel::Error, ## __VA_ARGS__)
#else 
#define LogError(...)   OUT_EMPTY() 
#define LogErrorIf(cond, ...)   OUT_EMPTY() 
#endif

#if LOGGER_CONFIG_LEVEL >= LOGGER_LEVEL_FATAL
#define LogFatal(...)        LogOut(Logger::Instance(), LoggerLevel::Fatal, ## __VA_ARGS__)
#define LogFatalIf(cond, ...)       if(cond)LogOut(Logger::Instance(), LoggerLevel::Fatal, ## __VA_ARGS__)
#else 
#define LogFatal(...)   OUT_EMPTY()
#define LogFatalIf(cond, ...)   OUT_EMPTY()
#endif

/**
* @class  Logger
* @brief  Log接口
* @author
* @note
*/
class Logger : protected NoneCopyable
{
    friend class MessageBuilder;

public:
    using WRITE_STREAM_FUNC = std::function<void(const char *buf, size_t len)>;

public:
    explicit Logger();
    explicit Logger(const std::string &name);
    virtual ~Logger();

    static Logger& Instance();
    
public:
    void ConfigUart(IF_SOC_Uart *uart, bool enabledDMA = false);
    void StartAsync();
    void StopAsync();

public:
    inline bool IsLogOn(LoggerLevel level)
    {
        return Configuration.LogEnable && 
               (int)level <= LOGGER_CONFIG_LEVEL;
    }

    MessageBuilder Output(LoggerLevel level);
    MessageBuilder Output(LoggerLevel level, const std::string &tag);
    MessageBuilder Output(LoggerLevel level,
                          const std::string &fileName,
                          int line,
                          const std::string &funcName,
                          const std::string &tag = "");

    //在不输出src info 下，提高性能
    template<typename... Args>
    MessageBuilder OutputArg(LoggerLevel level,
                             const Args&... args)
    {
        std::string tag;
        if(sizeof...(args) > 0)
            (void)std::initializer_list<std::string>{([&] {if(tag.empty()) tag = args; }(), "")...};//first param
        return Output(level, tag);
    }

    template<typename... Args>
    MessageBuilder OutputArg(LoggerLevel level,
                            const std::string &fileName,
                            int line,
                            const std::string &funcName, 
                            const Args&... args)
    {
        std::string tag;
        if(sizeof...(args) > 0)
            (void)std::initializer_list<std::string>{([&] {if(tag.empty()) tag = args; }(), "")...};//first param
        return Output(level, fileName, line, funcName, tag);
    }

private:
    void BeginWriteStream();
    void EndWriteStream();
    void WriteToStream(const char *buf, size_t len, bool lock = true);
    void DoWriteToStreamImpl(const char *buf, size_t len);
    void PostMsgToQueue(const char *buf, size_t len, int timeout = 0);

    void WriteStreamTask();

public:
    LoggerConfiguration Configuration;

private:
    class MsgItem
    {
    public:
        char *Buffer = nullptr;
        int Len = 0;
    };
    
private:
    IF_SOC_Uart *m_uart = nullptr;
    bool m_dmaEnabled = false;
    Mutex m_mutex;
    Thread m_thread{LOGGER_ASYNC_THREAD_STACK_SIZE};
    MsgQueue<MsgItem*, LOGGER_ASYNC_BUFFER_MAX> m_queue;

    std::string m_name = "default";
};

#endif // __LOGGER_H__
